class TrafficParticipants {
  constructor ({ map, url, areaId, startTime, endTime }) {
    this.map = map //地图容器
    this.startTime = startTime //查询起始时间
    this.endTime = endTime //查询结束时间
    this.vehicleHolder = {}
    this.isFirstPackge = false
    this.socket = undefined
    this.url = url
    this.isVisible = true
    this.queryTime = undefined
    this.areaId = areaId
    this.timeRange = 60000
    this.isQueryEnd = false
    this.heightLimit = 13000
    this.timePickerValue = [startTime, endTime]
    this.init()
  }

  init () {
    console.log("TrafficParticipants：开始创建socket连接！")
    this.socket = io(this.url)

    if (!this.socket.connected) {
      this.socket.connect()
    }

    this.socket.on("OnPMSG", (response) => {
      if (response === "END") {
        this.isQueryEnd = true
        // this.setVehicleStateToEnd()
      } else {
        const resArr = JSON.parse(response)
        const { vinList, source } = this.converData(resArr)
        if (source.length > 0 && !this.isInvalidData(source[0])) {
          if (this.isFirstPackge) {
            console.log("TrafficParticipants：开始接受数据！")
            this.removeAllCar()
            this.queryTime = Date.now()
            this.isFirstPackge = false
            this.createVehicleModels({ vinList, source })
          } else {
            this.updateVehicleData({ vinList, source })
          }
        }
      }
    })
    // 函数防抖
    function debounce (func, wait) {
      let timer
      return function () {
        const context = this // 注意 this 指向
        const args = arguments // arguments中存着e
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          func.apply(context, args)
        }, wait)
      }
    }
    //地图平移缩放监听
    this.map.camera.moveEnd.addEventListener(() => {
      const height = this.map.camera.positionCartographic.height
      const startTime = this.queryTime ? this.startTime + Date.now() - this.queryTime : this.startTime
      if (height < this.heightLimit) {
        if (startTime < this.endTime)
          debounce(() => {
            this.sendQueryMessage(startTime, this.endTime)
          }, 200)()
      } else {
        this.removeAllCar()
      }
    })
  }

  /**
   * 创建车辆模型
   * @param {Array<string>} vinList 车牌列表
   * @param {Array<Array<Object>>} source 车辆轨迹数据
   */
  createVehicleModels ({ vinList, source }) {
    source.forEach((item, index) => {
      if (item.length > 0) {
        const spp = new Cesium.SampledPositionProperty()
        const orien = new Cesium.SampledProperty(Cesium.Quaternion)
        item.forEach(({ timestamp, latitude, longitude, heading }) => {
          const time = Cesium.JulianDate.fromDate(new Date(timestamp))
          const c3 = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
          spp.addSample(time, c3)
          const o = Cesium.Transforms.headingPitchRollQuaternion(
            c3,
            new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(heading - 90), Cesium.Math.toRadians(0), Cesium.Math.toRadians(0)),
          )
          orien.addSample(time, o)
        })
        const vop = new Cesium.VelocityOrientationProperty(spp)
        this.vehicleHolder[vinList[index]] = this.map.entities.add({
          id: item[0]["vin"],
          position: spp,
          orientation: orien,
          model: {
            uri: "/data/car.gltf",
            color: Cesium.Color.WHITE,
            minimumPixelSize: 64,
            maximumScale: 20000,
          },
          label: {
            text: `ID:${item[0].vin}`,
            font: "normal 15px MicroSoft YaHei", // 字体样式
            fillColor: Cesium.Color.fromCssColorString("#9BD5FF"), // 字体颜色
            backgroundColor: Cesium.Color.fromCssColorString("#091C2E").withAlpha(0.2), // 背景颜色
            showBackground: true, // 是否显示背景颜色
            verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直位置
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT, // 水平位置
            pixelOffset: new Cesium.Cartesian2(20, 0),
            disableDepthTestDistance: 50000,
          },
          properties: {
            type: item[0]["tableType"],
          },
        })
      }
    })
    this.map.clock.shouldAnimate = true
    console.log("TrafficParticipants：创建车辆模型！")
  }
  /**
   * 更新车辆数据
   * @param {Array<string>} vinList 车牌列表
   * @param {Array<Array<Object>>} source 车辆轨迹数据
   */
  updateVehicleData ({ vinList, source }) {
    console.log("TrafficParticipants：更新车辆数据！")
    vinList.forEach((vin, index) => {
      const va = source[index]
      const vehicle = this.vehicleHolder[vin]
      if (vehicle) {
        const spp = vehicle.position
        const orien = vehicle.orientation
        va.forEach(({ timestamp, latitude, longitude, heading }) => {
          const time = Cesium.JulianDate.fromDate(new Date(timestamp))
          const c3 = Cesium.Cartesian3.fromDegrees(Number(longitude), Number(latitude), 0)
          spp.addSample(time, c3)
          const o = Cesium.Transforms.headingPitchRollQuaternion(
            c3,
            new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(heading - 90), Cesium.Math.toRadians(0), Cesium.Math.toRadians(0)),
          )
          orien.addSample(time, o)
        })
        // vehicle.orientation = new Cesium.VelocityOrientationProperty(spp);
      }
    })
    const addVehicleData = this.getAddVehicleData(vinList, source)
    this.createVehicleModels(addVehicleData)
  }
  /** 删除所有车辆*/
  removeAllCar () {
    const keys = Object.keys(this.vehicleHolder)
    keys.forEach((key) => {
      this.map.entities.remove(this.vehicleHolder[key])
    })
    this.vehicleHolder = {}
  }
  /**控制所有车辆显示隐藏 */
  controlAllVehiclesVisible (visible) {
    const keys = Object.keys(this.vehicleHolder)
    keys.forEach((key) => {
      this.vehicleHolder[key].show = visible
    })
    console.log("TrafficParticipants：" + visible ? "显示" : "隐藏" + "车辆！")
  }
  /**发送请求 */
  sendQueryMessage (startTime, endTime, isTimePickerSource = false) {
    if (isTimePickerSource) this.timePickerValue = [startTime, endTime]
    if (this.socket) {
      console.log("TrafficParticipants：发送请求！")
      this.startTime = startTime
      this.endTime = endTime
      this.isQueryEnd = false
      const [xmin, ymin, xmax, ymax] = this.getRange()
      if (xmin && ymin && xmax && ymax)
        this.socket.emit("onClientTrafficParticipant", {
          vehicleQueryVo: JSON.stringify({
            regionId: this.areaId,
            timeRange: this.timeRange,
            startTime,
            endTime,
            range: [
              [xmin, ymax],
              [xmax, ymax],
              [xmax, ymin],
              [xmin, ymin],
            ],
          }),
        })
      this.isFirstPackge = true
    }
  }
  /**获取地图当前可视范围 */
  getRange () {
    const map = this.map
    const extend = map.camera.computeViewRectangle()
    const coordToLonlat = (x, y) => {
      const { camera, scene } = map
      const d2 = new Cesium.Cartesian2(x, y)
      const ellipsoid = scene.globe.ellipsoid
      // 2D转3D世界坐标
      const d3 = camera.pickEllipsoid(d2, ellipsoid)
      // 3D世界坐标转弧度
      const upperLeftCartographic = scene.globe.ellipsoid.cartesianToCartographic(d3)
      // 弧度转经纬度
      const lng = Cesium.Math.toDegrees(upperLeftCartographic.longitude)
      const lat = Cesium.Math.toDegrees(upperLeftCartographic.latitude)
      return { lng, lat }
    }
    if (extend) {
      const west = Cesium.Math.toDegrees(extend.west)
      const south = Cesium.Math.toDegrees(extend.south)
      const east = Cesium.Math.toDegrees(extend.east)
      const north = Cesium.Math.toDegrees(extend.north)
      return [west, south, east, north]
    } else {
      const canvas = map.scene.canvas
      const upperLeftLonLat = coordToLonlat(0, 0)
      const lowerRightLonLat = coordToLonlat(canvas.clientWidth, canvas.clientHeight)
      const xmin = upperLeftLonLat.lng
      const ymax = upperLeftLonLat.lat
      const xmax = lowerRightLonLat.lng
      const ymin = lowerRightLonLat.lat
      return [xmin, ymin, xmax, ymax]
    }
  }
  /**转换数据 */
  converData (data) {
    const vinList = []
    const source = []
    data.forEach(({ timestamp, vin, latitude, longitude, heading, tableType }) => {
      let va
      if (vinList.includes(vin)) {
        va = source[vinList.indexOf(vin)]
      } else {
        vinList.push(vin)
        va = []
        source.push(va)
      }
      va.push({
        timestamp: timestamp,
        vin,
        latitude,
        longitude,
        heading,
        tableType,
      })
    })
    source.forEach((item) => {
      item.sort((a, b) => {
        return a - b
      })
    })
    return {
      vinList,
      source,
    }
  }
  /**判断数据是否是无效数据 */
  isInvalidData (data) {
    return data[data.length - 1].timestamp < this.startTime
  }
  /**轨迹播放结束 */
  /**获取新增车辆编号集合 */
  getAddVehicleData (vinList, source) {
    const keys = Object.keys(this.vehicleHolder)
    const addV = []
    const addSource = []
    vinList.forEach((vin, index) => {
      if (!keys.includes(vin)) {
        addV.push(vin)
        addSource.push(source[index])
      }
    })
    return {
      vinList: addV,
      source: addSource,
    }
  }
  /**销毁 */
  destroy () {
    this.socket.disconnect();
    this.socket.close();
    this.removeAllCar();
  }
}

export default TrafficParticipants
